//
// Created by Max on 2025/5/13.
//

#include "AnalysisFile.h"
#include "Properties.h"
#include <math.h>
#include "fftw3.h"
#include "../MicLoader.h"
#include <numeric>

#define DETECT_FILE_FREQUENCY 500

static std::string g_FilePath = "/storage/emulated/0/recorder/";

AnalysisFile::AnalysisFile() {

}

AnalysisFile::~AnalysisFile() {

}

bool AnalysisFile::checkMic(std::vector<double> &value) {

    char propDb[PROPERTY_KEY_MAX] = {0};
    char dataDb[PROPERTY_VALUE_MAX] = {0};

    std::vector<double>::iterator maxValue = std::max_element(value.begin(), value.end());
    std::vector<double>::iterator minValue = std::min_element(value.begin(), value.end());

    for (int i = 0; i < value.size(); i++) {
        memset(propDb, 0, PROPERTY_KEY_MAX);
        memset(dataDb, 0, PROPERTY_VALUE_MAX);
        sprintf(propDb, "mic_ch%d_db", i);
        sprintf(dataDb, "%.2f", value[i]);
        Properties::instance()->property_set(propDb, dataDb);
    }

    if ((*minValue < -40.0) || (*maxValue - *minValue) > 4.0) {

        return false;
    }
    return true;
}

int AnalysisFile::getFileSize(const char *fileName) {
    uint32_t size = 0;
    FILE *fp = fopen(fileName, "rb");
    if (fp == NULL) {
        LOGE("open file error\n");
        return -1;
    }
    fseek(fp, 0, SEEK_END);
    size = ftell(fp);
    fclose(fp);
    return size;
}

int AnalysisFile::wav2Pcm(const char *wavFile, const char *pcmFile) {
    size_t ret = 0;
    // wav file size
    uint32_t wav_file_size = 0;
    // fp
    FILE *fp_pcm_file, *fp_wav_file;
    // buffer
    unsigned char *read_data;

    fp_wav_file = fopen(wavFile, "rb");
    if (fp_wav_file == nullptr) {
        LOGE("open file == %s error\n", wavFile);
        return -1;
    }
    fp_pcm_file = fopen(pcmFile, "wb");
    if (fp_pcm_file == nullptr) {
        LOGE("open file == %s error\n", pcmFile);
        return -1;
    }
    wav_file_size = getFileSize(wavFile);
    read_data = (unsigned char *) malloc(wav_file_size * sizeof(unsigned char));
    if (read_data == NULL) {
        LOGE("malloc error\n");
        return -1;
    }
    // wav文件的指针从头向后移动44字节 wav header 44 byte
    fseek(fp_wav_file, 44, SEEK_SET);
    ret = fread(read_data, sizeof(unsigned char), (wav_file_size - 44), fp_wav_file);

    if (ret != wav_file_size - 44) {
        LOGE("count != \n");
        return -1;
    }
    // 写到pcm文件中
    fwrite(read_data, sizeof(unsigned char), (wav_file_size - 44), fp_pcm_file);

    fclose(fp_wav_file);
    fclose(fp_pcm_file);
    free(read_data);
    return 0;
}

int AnalysisFile::departChannel(const char *fileName, int channelIndex, int channelMaxNum) {

    char file_name[48] = {0};
    sprintf(file_name, "%d%s", channelIndex, ".pcm");

    const std::string pcmName = g_FilePath + std::string(file_name);
    FILE *fp = fopen(fileName, "rb");
    if (fp == nullptr) {
        LOGE("fopen %s error\n", fileName);
        return -1;
    }

    FILE *fp0 = fopen(pcmName.c_str(), "wb");
    if (fp0 == nullptr) {
        LOGE("fopen %s error\n", pcmName.c_str());
        return -1;
    }
    unsigned char *sample = (unsigned char *) malloc(2 * channelMaxNum);
    while (!feof(fp)) {

        size_t len = fread(sample, 1, 2 * channelMaxNum, fp);
        if (len != 2 * channelMaxNum && len > 0) {
            LOGE("read error len === %zu \n", len);
            break;
        }
        fwrite(sample + 2 * channelIndex, 1, 2, fp0);
    }

    LOGE("depart file path = %s\n", pcmName.c_str());
    free(sample);
    fclose(fp);
    fclose(fp0);
    return 0;
}

int AnalysisFile::fftChannel(const char *path, int fftSize, int sampleRate, double &dbValue) {
    short read_buffer[fftSize];

    const std::string pcmName = g_FilePath + std::string(path);
    // 读取输入音频数据，这里假设从文件读取，你可以根据需要进行修改

    size_t size = getFileSize(pcmName.c_str());
    LOGE("%s size = %zu", pcmName.c_str(), size);

    long offset = (size / 2);
    if (offset % 2 != 0) {
        offset = offset + 1;
    }
    LOGE("%s offset = %ld", pcmName.c_str(), offset);

    FILE *input_file = fopen(pcmName.c_str(), "rb");
    fseek(input_file, offset, SEEK_SET);
    size_t num = fread(read_buffer, sizeof(short), fftSize, input_file);

    // 创建 FFTW 输入和输出数组
    fftw_complex *fft_input = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * fftSize);
    fftw_complex *fft_output = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * fftSize);

    // 创建 FFTW 3.0 的计划
    fftw_plan plan = fftw_plan_dft_1d(fftSize, fft_input, fft_output, FFTW_FORWARD, FFTW_ESTIMATE);
    for (int i = 0; i < fftSize; i++) {
        fft_input[i][0] = (double) read_buffer[i];
        fft_input[i][1] = 0.0; // 虚部设置为零
    }

    // 执行频域变换
    fftw_execute(plan);

    int index = fftSize * DETECT_FILE_FREQUENCY / sampleRate;
    double amplitude = sqrt(fft_output[index][0] * fft_output[index][0] +
                            fft_output[index][1] * fft_output[index][1]);
    dbValue = 20 * log10(amplitude / (32768 * (fftSize / 2)));

    LOGD("%s channel db = %f", path, dbValue);

    // 销毁 FFTW 相关资源
    fftw_destroy_plan(plan);
    fftw_free(fft_input);
    fftw_free(fft_output);

    fclose(input_file);
    return 0;
}

int AnalysisFile::getDb(const char *path, int fftSize, int sampleRate, int offset, double &dbValue) {
    short read_buffer[fftSize];

    const std::string pcmName = g_FilePath + std::string(path);
    // 读取输入音频数据，这里假设从文件读取，你可以根据需要进行修改

    FILE *input_file = fopen(pcmName.c_str(), "rb");
    fseek(input_file, offset, SEEK_SET);
    fread(read_buffer, sizeof(short), fftSize, input_file);

    // 创建 FFTW 输入和输出数组
    fftw_complex *fft_input = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * fftSize);
    fftw_complex *fft_output = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * fftSize);

    // 创建 FFTW 3.0 的计划
    fftw_plan plan = fftw_plan_dft_1d(fftSize, fft_input, fft_output, FFTW_FORWARD, FFTW_ESTIMATE);
    for (int i = 0; i < fftSize; i++) {
        fft_input[i][0] = (double) read_buffer[i];
        fft_input[i][1] = 0.0; // 虚部设置为零
    }

    // 执行频域变换
    fftw_execute(plan);

    int index = fftSize * DETECT_FILE_FREQUENCY / sampleRate;
    double amplitude = sqrt(fft_output[index][0] * fft_output[index][0] +
                            fft_output[index][1] * fft_output[index][1]);
    dbValue = 20 * log10(amplitude / (32768 * (fftSize / 2)));

    LOGD("%s channel db = %f", path, dbValue);

    // 销毁 FFTW 相关资源
    fftw_destroy_plan(plan);
    fftw_free(fft_input);
    fftw_free(fft_output);

    fclose(input_file);

    return 0;
}

int AnalysisFile::fftChannel(const char *path,int loopNum,double &dbValue) {
    const std::string pcmName = g_FilePath + std::string(path);
    vector<double> totalDb;
    size_t size = getFileSize(pcmName.c_str());
    LOGE("%s size = %zu", pcmName.c_str(), size);

    for (int i = 1;i<loopNum;i++) {
        double db;
        long offset = ((size * i) / loopNum);
        if (offset % 2 != 0) {
            offset = offset + 1;
        }
        LOGE("%s offset = %ld", pcmName.c_str(), offset);
        getDb(path,1024,16000,offset,db);
        LOGE("get db value === %f",db);
        totalDb.push_back(db);
    }

    dbValue = (std::accumulate(totalDb.begin(),totalDb.end(),0.0) )/ totalDb.size();
    LOGE("get dbValue value === %f",dbValue);
    return 0;
}
